﻿
// <copyright file="ProgressDisplayUserControl.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The progress display user control.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Windows.Forms
{
    using System;
    using System.Globalization;
    using System.Threading;
    using System.Windows.Forms;

    using SubhadraSolutions.Sharp.Utils.Diagnostics;

    /// <summary>
    /// The progress display user control.
    /// </summary>
    public partial class ProgressDisplayUserControl : UserControl
    {
        #region Fields

        /// <summary>
        /// The completed items.
        /// </summary>
        private int _completedItems;

        /// <summary>
        /// The ticks elapsed at starting.
        /// </summary>
        private long _ticksElapsedAtStarting;

        /// <summary>
        /// The total number of items.
        /// </summary>
        private int _totalNumberOfItems;

        #endregion Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes a new instance of the <see cref="ProgressDisplayUserControl"/> class.
        /// </summary>
        public ProgressDisplayUserControl()
        {
            this.InitializeComponent();
        }

        #endregion Constructors and Finalizers

        #region Public Events

        /// <summary>
        /// The on all completed.
        /// </summary>
        public event EventHandler OnAllCompleted;

        #endregion Public Events

        #region Public Properties

        /// <summary>
        /// Gets the completed items.
        /// </summary>
        public int CompletedItems
        {
            get
            {
                return Thread.VolatileRead(ref this._completedItems);
            }
        }

        /// <summary>
        /// Gets the progress in percentage.
        /// </summary>
        public decimal ProgressInPercentage
        {
            get
            {
                if (this.TotalNumberOfItems == 0)
                {
                    return 100;
                }

                int completedItems = this.CompletedItems;
                if (completedItems == this.TotalNumberOfItems)
                {
                    return 100;
                }

                if (completedItems == 0)
                {
                    return 0;
                }

                decimal percentage = (100 * ((decimal)completedItems)) / this.TotalNumberOfItems;
                if (percentage == decimal.Truncate(percentage))
                {
                    return percentage;
                }

                return decimal.Round(percentage, 2);
            }
        }

        /// <summary>
        /// Gets the remaining items.
        /// </summary>
        public int RemainingItems
        {
            get
            {
                return this.TotalNumberOfItems - this.CompletedItems;
            }
        }

        /// <summary>
        /// Gets the total number of items.
        /// </summary>
        public int TotalNumberOfItems
        {
            get
            {
                return this._totalNumberOfItems;
            }
        }

        #endregion Public Properties

        #region Public Methods and Operators

        /// <summary>
        /// The increment.
        /// </summary>
        public void Increment()
        {
            Interlocked.Increment(ref this._completedItems);
        }

        /// <summary>
        /// The initialize.
        /// </summary>
        /// <param name="totalNumberOfItems">
        /// The total number of items.
        /// </param>
        /// <param name="refreshIntervalInMilliseconds">
        /// The refresh interval in milliseconds.
        /// </param>
        public void Initialize(int totalNumberOfItems, int refreshIntervalInMilliseconds)
        {
            this._totalNumberOfItems = totalNumberOfItems;
            this.totalLabel.Text = totalNumberOfItems.ToString(CultureInfo.InvariantCulture);
            this.progressBar1.Minimum = 0;
            this.progressBar1.Maximum = this._totalNumberOfItems;

            Thread.VolatileWrite(ref this._completedItems, 0);
            this.timer1.Interval = refreshIntervalInMilliseconds;
            this._ticksElapsedAtStarting = SharedStopWatch.ElapsedTicks;

            this.timer1.Start();
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The timer 1_ tick.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            this.SuspendLayout();
            this.completedLabel.Text = this.CompletedItems.ToString(CultureInfo.InvariantCulture);
            this.remainingLabel.Text = this.RemainingItems.ToString(CultureInfo.InvariantCulture);
            this.percentageLabel.Text = this.ProgressInPercentage + "%";
            this.progressBar1.Value = this.CompletedItems;
            long ticksElapsed = Math.Max(1, SharedStopWatch.ElapsedTicks - this._ticksElapsedAtStarting);
            if (this.CompletedItems > 0)
            {
                long remainingTicks = (this.RemainingItems * ticksElapsed) / this.CompletedItems;
                TimeSpan timeSpanRemaining = TimeSpan.FromTicks(remainingTicks);
                this.timeRemainingLabel.Text = StringHelper.TimeSpanToString(timeSpanRemaining);
            }
            else
            {
                this.timeRemainingLabel.Text = "∞";
            }

            TimeSpan timeSpanElapsed = TimeSpan.FromTicks(ticksElapsed);
            this.timeElapsedLabel.Text = StringHelper.TimeSpanToString(timeSpanElapsed);
            if (this.CompletedItems == this._totalNumberOfItems)
            {
                this.timer1.Stop();
                if (this.OnAllCompleted != null)
                {
                    this.OnAllCompleted(this, EventArgs.Empty);
                }
            }

            this.ResumeLayout();
        }

        #endregion Methods
    }
}